Windows驱动编程之WFP/TDI
看雪论坛作者ID:一半人生
1
2
TDI三类:
1、Afd.sys,NetBt.sys,Http.sys都属于TDI客户端驱动。
2、过滤则是我们自己创建的过滤设备,防火墙就是一个最典型的过滤产品。
3、传输驱动通常实现传输层和网络层功能,处理TDI客户端IRP等,是通过NDIS网络适配访问,如TCPIP.sys,NWLINK.sys,TCPIP6.sys都是TDI驱动。
TDI设备对象:
3
很重要的一部分,看上述的图,Client到Transport,Filter可有可无,那么既然说了是网络,定然有交互协议约定。TDI传输依赖IRP与Callback,TDI Client使用IRP,而TDI Transport用EventCallback。
TDI事件通知:
1、TCP Client发送IRP到TCP Transport,这个地方TDI Transport返回STATUS_PENDING状态,之后在某个特定事件发生完成IRP,然后回调函数调用处理,这种是客户请求。主动注册需要发送TDI_RECEIVE_IRP胡策一个TDI_EVENT_RECEIVE回调。
2、另一种需要TDI提前注册好回调函数等待被触发,当特定事件发生时调用处理,这种是事件。
TDI IRP:
TDI Client side TDI Transport:
1、ZwCreateFile创建传输地址对象
2、注册事件
3、创建一系列连接端点对象ZwCreateFile
4、关键起来TDI_ASSOCIATE_ADDRESS
5、当需要处理函数,被调用时,检查远端信息,选择可用的远程连接端去发起响应请求(TDI_ACCEPT)
4
概念性请参考msdn:
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/network/roadmap-for-developing-wfp-callout-drivers
5
wfp-tcp抓包:
本篇是以前学习编写的demo示例,Wfp再应用层和内核层都提供了API,本套代码逻辑User负责添加Callout,Sublayer及filter,内核层负责注册Callout。
r3:
// OpenEngine
result = HlprFwpmEngineOpen(&engineHandle, &session);
if (NO_ERROR != result)
{
printf("Error: HlprFwpmEngineOpen = %d\r\n", result);
return -1;
}
// TransactionBegin
result = HlprFwpmTransactionBegin(&engineHandle);
if (NO_ERROR != result)
{
printf("Error: HlprFwpmTransactionBegin = %d\r\n", result);
return -1;
}
RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));
RtlZeroMemory(&displayData, sizeof(FWPM_DISPLAY_DATA));
displayData.description = MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION;
displayData.name = MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME;
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
FwpmCalloutAdd0(
_In_ HANDLE engineHandle,
_In_ const FWPM_CALLOUT0* callout,
_In_opt_ PSECURITY_DESCRIPTOR sd,
_Out_opt_ UINT32* id
);
typedef struct FWPM_CALLOUT0_
{
GUID calloutKey;
FWPM_DISPLAY_DATA0 displayData;
UINT32 flags;
/* [unique] */ GUID *providerKey;
FWP_BYTE_BLOB providerData;
GUID applicableLayer;
UINT32 calloutId;
} FWPM_CALLOUT0;
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4/V6 关联TCP上下文数据包
FWPM_LAYER_STREAM_V4/V6 监控发送流量,如send/sendto
FWPM_SUBLAYER TcpSubLayer, UdpSubLayer;
// FWPM_SUBLAYER monitorUdpICMPSubLayer;
FWPM_FILTER Tcpfilter, Udpfilter;
FWPM_FILTER_CONDITION TcpSublayerfilterConditions[3] = { 0, }, UdpSublayerfilterConditions[3] = { 0, }; // We only need two for this call.
过滤条件:
RtlZeroMemory(TcpSublayerfilterConditions, sizeof(TcpSublayerfilterConditions));
TcpSublayerfilterConditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
TcpSublayerfilterConditions[0].matchType = FWP_MATCH_EQUAL; // 是否等于条件值
TcpSublayerfilterConditions[0].conditionValue.type = FWP_UINT8;
TcpSublayerfilterConditions[0].conditionValue.uint8 = IPPROTO_TCP; // TCP
RtlZeroMemory(&Tcpfilter, sizeof(FWPM_FILTER));
Tcpfilter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
Tcpfilter.displayData.name = L"Flow established filter.";
Tcpfilter.displayData.description = L"Sets up flow for traffic that we are interested in.";
Tcpfilter.action.type = FWP_ACTION_CALLOUT_TERMINATING; // FWP_ACTION_CALLOUT_INSPECTION
Tcpfilter.action.calloutKey = TCP_FLOW_ESTABLISHED_CALLOUT_V4;
Tcpfilter.filterCondition = TcpSublayerfilterConditions;
Tcpfilter.subLayerKey = MONITOR_SAMPLE_SUBLAYER;
Tcpfilter.weight.type = FWP_EMPTY; // auto-weight.
Tcpfilter.numFilterConditions = 1;
printf("HlprFwpmFilterAdd engineHandle = 0x%p\n", *engineHandle);
result = HlprFwpmFilterAdd(engineHandle, &Tcpfilter);
if (NO_ERROR != result)
break;
r0:
#if (NTDDI_VERSION >= NTDDI_WIN7)
// Register the function pointers for a version-1 callout. The callout driver
// must call FwpsCalloutUnregisterById before unloading.
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
NTAPI
FwpsCalloutRegister1(
_Inout_ void* deviceObject,
_In_ const FWPS_CALLOUT1* callout,
_Out_opt_ UINT32* calloutId
);
#endif // (NTDDI_VERSION >= NTDDI_WIN7)
FWPS_CALLOUT sCallout;NTSTATUS status = STATUS_SUCCESS;memset(&sCallout, 0, sizeof(FWPS_CALLOUT));sCallout.calloutKey = *calloutKey;sCallout.flags = flags;sCallout.classifyFn = ClassifyFunction;sCallout.notifyFn = NotifyFunction;sCallout.flowDeleteFn = FlowDeleteFunction;
_In_ const FWPS_INCOMING_VALUES* inFixedValues,_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
进程路径inMetaValues->processPath五要素inFixedValues->incomingValue[index].value.uint32;incomingValue是一个数组,index获取不同的元素:typedef enum FWPS_FIELDS_ALE_FLOW_ESTABLISHED_V4_{ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_APP_ID, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_USER_ID, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS_TYPE, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_REMOTE_USER_ID, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_REMOTE_MACHINE_ID, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_DESTINATION_ADDRESS_TYPE, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_INTERFACE, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_INTERFACE_TYPE, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_TUNNEL_TYPE,#if (NTDDI_VERSION >= NTDDI_WIN6SP1) FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS,#if (NTDDI_VERSION >= NTDDI_WIN8) FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_ORIGINAL_APP_ID, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_PACKAGE_ID,#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE,#if (NTDDI_VERSION >= NTDDI_WIN10_RS2) FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_COMPARTMENT_ID,#endif // (NTDDI_VERSION >= NTDDI_WIN10_RS2)#endif // (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)#endif // (NTDDI_VERSION >= NTDDI_WIN8)#endif // (NTDDI_VERSION >= NTDDI_WIN6SP1) FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_BITMAP_IP_LOCAL_ADDRESS, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_BITMAP_IP_LOCAL_PORT, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_BITMAP_IP_REMOTE_ADDRESS, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_BITMAP_IP_REMOTE_PORT, FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_MAX} FWPS_FIELDS_ALE_FLOW_ESTABLISHED_V4;
status = FwpsFlowAssociateContext(flowHandle, FWPS_LAYER_STREAM_V4, // 关联到stream_v4层 streamId, // 层id flowContextLocal); // 保存的元素
_Inout_opt_ void* packet
streamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)packet;
if (streamPacket->streamData != NULL && streamPacket->streamData->dataLength != 0)
{
flowData = *(FLOW_DATA**)
(UINT64*)&flowContext;
inbound = (BOOLEAN)((streamPacket->streamData->flags &
FWPS_STREAM_FLAG_RECEIVE) == FWPS_STREAM_FLAG_RECEIVE);
DbgPrint("Tcp --> ProcessId : %d\t Protor: %d\t localAddressV4: 0x%x:%d\t remoteAddressV4: 0x%x:%d\r\n", flowData->processID, flowData->ipProto, flowData->localAddressV4, flowData->localPort, flowData->remoteAddressV4, flowData->remotePort);
classifyOut->actionType = FWP_ACTION_CONTINUE;
需要转才可以
ULONG blockipaddrArry[10] = { 0xb465310b,0, };
if (flowData->remoteAddressV4 == blockipaddrArry[0]) {
classifyOut->actionType = FWP_ACTION_BLOCK;
return status;
}
FPWM_LAYER_ALE_CONNECT_REDIRECT
1、Windows驱动编程之串口过滤杂谈: https://xz.aliyun.com/t/6487
2、Windows驱动编程之键盘过滤杂谈: https://xz.aliyun.com/t/6581
看雪ID:一半人生
https://bbs.pediy.com/user-home-819685.htm
*本文由看雪论坛 一半人生 原创,转载请注明来自看雪社区
# 往期推荐
1. 记一次MEMZ样本分析
2. Dex起步探索
球分享
球点赞
球在看
点击“阅读原文”,了解更多!